// ConsoleHost.cpp : Defines the entry point for the DLL application.
//

#include "stdafx.h"

#include "ConsoleHandler.h"
#include "ConsoleHost.h"

//////////////////////////////////////////////////////////////////////////////

shared_ptr<SettingsHandler>	g_settingsHandler;

std::vector<shared_ptr<ConsoleHost> > g_hosts;

//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////

BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID /* lpReserved */)
{
	switch (ul_reason_for_call)
	{
		case DLL_PROCESS_ATTACH:
		{
			g_hModule = (HMODULE)hModule;
			// g_consoleHandler.StartMonitorThread();
			g_settingsHandler.reset(new SettingsHandler());

			break;
		}

		case DLL_THREAD_ATTACH:
			break;

		case DLL_THREAD_DETACH:
			break;

		case DLL_PROCESS_DETACH:

			g_settingsHandler.reset();
			g_hosts.clear();
			// g_consoleHandler.StopMonitorThread();
			TRACE(L"Hook exiting!\n");
			break;
	}

	return TRUE;
}

//////////////////////////////////////////////////////////////////////////////

CONSOLEHOST_API ConsoleHost* CreateConsoleHost()
{
	shared_ptr<ConsoleHost> host(new ConsoleHost());
	g_hosts.push_back(host);

	host->_consoleHandler = new ConsoleHandler();

	return host.get();
}

CONSOLEHOST_API void DeleteConsoleHost(ConsoleHost *host)
{
	std::vector<shared_ptr<ConsoleHost> >::iterator itHosts;

	for (itHosts = g_hosts.begin(); itHosts != g_hosts.end(); ++itHosts)
	{
		shared_ptr<ConsoleHost> h = *itHosts;
		if(h.get() == host)
		{
			g_hosts.erase(itHosts);
			return;
		}
	}

}

CONSOLEHOST_API ConsoleHost::~ConsoleHost()
{
	delete this->_consoleHandler;
}


CONSOLEHOST_API void ConsoleHost::SetupDelegates(void (consoleChangedCallback) (bool) , void (consoleCloseDelegate)())
{
	_consoleHandler->SetupDelegates(consoleChangedCallback, consoleCloseDelegate);
}

CONSOLEHOST_API bool ConsoleHost::StartShellProcess(LPCTSTR strCustomShell, LPCTSTR strInitialDir, LPCTSTR strConsoleTitle, DWORD dwStartupRows, DWORD dwStartupColumns)
{
	return _consoleHandler->StartShellProcess(strCustomShell, strInitialDir, strConsoleTitle, dwStartupRows, dwStartupColumns);
}

CONSOLEHOST_API DWORD ConsoleHost::StartMonitorThread()
{
	return _consoleHandler->StartMonitorThread();
}
CONSOLEHOST_API	void ConsoleHost::StopMonitorThread()
{
	_consoleHandler->StopMonitorThread();
}

CONSOLEHOST_API ConsoleParams* ConsoleHost::GetConsoleParams()
{
	return _consoleHandler->GetConsoleParams().Get();
}

CONSOLEHOST_API CHAR_INFO* ConsoleHost::GetConsoleBuffer()
{
	return _consoleHandler->GetConsoleBuffer().Get();
}

CONSOLEHOST_API	void ConsoleHost::GetConsoleSize(int* outCols, int* outRows)
{
	*outCols = _consoleHandler->GetNewConsoleSize()->dwColumns;
	*outRows = _consoleHandler->GetNewConsoleSize()->dwRows;
}
CONSOLEHOST_API	void ConsoleHost::SetConsoleSize(int cols, int rows)
{
	SharedMemoryLock memLock(_consoleHandler->GetNewConsoleSize());
	_consoleHandler->GetNewConsoleSize()->dwColumns	= cols;
	_consoleHandler->GetNewConsoleSize()->dwRows	= rows;
	_consoleHandler->GetNewConsoleSize().SetEvent();
}
CONSOLEHOST_API CONSOLE_SCREEN_BUFFER_INFO* ConsoleHost::GetConsoleInfo()
{
	return _consoleHandler->GetConsoleInfo().Get();
}

CONSOLEHOST_API	void ConsoleHost::SetScrollPosition(int cols, int rows)
{
	SharedMemory<SIZE>& newScrollPos = _consoleHandler->GetNewScrollPos();

	newScrollPos->cx = cols;
	newScrollPos->cy = rows;

	newScrollPos.SetEvent();

}

CONSOLEHOST_API	void ConsoleHost::SendTextToConsole(LPCWSTR pszText)
{
	if (!pszText || (wcslen(pszText) == 0)) return;

	void* pRemoteMemory = ::VirtualAllocEx(
								_consoleHandler->GetConsoleHandle().get(),
								NULL, 
								(wcslen(pszText)+1)*sizeof(wchar_t), 
								MEM_COMMIT, 
								PAGE_READWRITE);

	if (pRemoteMemory == NULL) return;

	if (!::WriteProcessMemory(
				_consoleHandler->GetConsoleHandle().get(),
				pRemoteMemory, 
				(PVOID)pszText, 
				(wcslen(pszText)+1)*sizeof(wchar_t), 
				NULL))
	{
		::VirtualFreeEx(_consoleHandler->GetConsoleHandle().get(), pRemoteMemory, NULL, MEM_RELEASE);
		return;
	}

	_consoleHandler->GetConsolePasteInfo() = reinterpret_cast<UINT_PTR>(pRemoteMemory);
	_consoleHandler->GetConsolePasteInfo().SetEvent();

}

